<!DOCTYPE html>
<html lang="zh-CN" class="uk-height-1-1">

<head>
{% include head.html %}
</head>

<style>
body {
    height: 100%;
    overflow: auto;
}

#content {
    padding: 10px 10px 10px 10px;
    /* min-height: calc(100% - 157px); */
    min-height: calc(100% - 157px + 30px);
}

footer {
    height: 95px; 
    background-color: #eee;
}
</style>
<body>
    <header>
        <div id="iiie"></div>
        <script>
            IIIE = new Vue({el:"#iiie"});
        </script>
        <script>
            if (typeof IIIE == 'undefined') {
                alert("该网页不支持您的浏览器版本，推荐使用 chrome 浏览器")
            }
        </script>
         {% include the-gfw.html %}
         {% include header.html %}
         {% include goTop.html %}
     </header>
     <hr style="margin:0">
     <style type="text/css">
        .json_key {
            color: #92278f;
            font-weight: bold;
        }
        .json_string {
            color: #3ab54a;
            font-weight: bold;
        }
        .json_link {
            color: #61D2D6;
            font-weight: bold;
            text-decoration:none;
        }
        .json_link:hover {
            color: #005599;
            font-weight: bold;
            text-decoration:none;
        }
        .json_number {
            color: #25aae2;
            font-weight: bold;
        }
        .json_boolean {
            color: #f98280;
            font-weight: bold;
        }
        .json_null {
            color: #ccc;
            font-weight: bold;
        }
        .fold_icon{
            font-size: 12px;
            color: #ccc;
        }
        #json_src {
            word-break: break-all;
            height: 100%;
            resize: vertical;
            padding: 10px;
            font-size: 13px;
            font-family: Consolas, monospace;
        }
        #json_result {
            font-family: Consolas, monospace;
        }
        @media (min-width: 960px) {
            #content {
                display: flex;
            }
            #json_src_box {
                width: 38%;
            }
            #json_result_box {
                padding-left: 10px;
                width: 62%;
            }
        }
        @media (max-width: 960px) {
            #json_src_box {
                width: 100%;
                height: 200px;
            }
            #json_result_box {
                margin-top: 10px;
                width: 100%;
            }
        }
        </style>
        <script>
        if (!String.prototype.repeat) {
          String.prototype.repeat = function(count) {
            'use strict';
            if (this == null)
              throw new TypeError('can\'t convert ' + this + ' to object');
        
            var str = '' + this;
            // To convert string to integer.
            count = +count;
            // Check NaN
            if (count != count)
              count = 0;
        
            if (count < 0)
              throw new RangeError('repeat count must be non-negative');
        
            if (count == Infinity)
              throw new RangeError('repeat count must be less than infinity');
        
            count = Math.floor(count);
            if (str.length == 0 || count == 0)
              return '';
        
            // Ensuring count is a 31-bit integer allows us to heavily optimize the
            // main part. But anyway, most current (August 2014) browsers can't handle
            // strings 1 << 28 chars or longer, so:
            if (str.length * count >= 1 << 28)
              throw new RangeError('repeat count must not overflow maximum string size');
        
            var maxCount = str.length * count;
            count = Math.floor(Math.log(count) / Math.log(2));
            while (count) {
               str += str;
               count--;
            }
            str += str.substring(0, maxCount - str.length);
            return str;
          }
        }
        
        if (!String.prototype.startsWith) {
            Object.defineProperty(String.prototype, 'startsWith', {
                value: function(search, pos) {
                    pos = !pos || pos < 0 ? 0 : +pos;
                    return this.substring(pos, pos + search.length) === search;
                }
            });
        }
        if (!String.prototype.endsWith) {
            String.prototype.endsWith = function(search, this_len) {
                if (this_len === undefined || this_len > this.length) {
                    this_len = this.length;
                }
                return this.substring(this_len - search.length, this_len) === search;
            };
        }
        </script>
     <div id="content">
         {{content}}
     </div>

<script>
        function hideIcon() {
            $('.uk-icon-angle-right').hide();
            $('.uk-icon-angle-down').hide();
        }
        function showIcon() {
            $('.uk-icon-angle-right').show();
            $('.uk-icon-angle-down').show();
        }
        function fold(icon) {
            icon.classList.remove('uk-icon-angle-down')
            icon.classList.add('uk-icon-angle-right')
            icon.setAttribute('onClick', 'javascript: unFold(this)')
            icon.childNodes[0].style.display = 'inline'
            icon.nextSibling.style.display = 'none'
        }
        function unFold(icon) {
            icon.classList.remove('uk-icon-angle-right')
            icon.classList.add('uk-icon-angle-down')
            icon.setAttribute('onClick', 'javascript: fold(this)')
            icon.childNodes[0].style.display = 'none'
            icon.nextSibling.style.display = 'inline'
        }
        var vm = new Vue({
            el: "#content",
            data: {
                reLink: /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig,
                reLastComma: /,(\s*[}\]])/g,
                cursorPosition: '?',
                jsonSrc: '{"hello":"搜索引擎排名不太稳定，加入书签 方便下次打开。","特性列表":["多种复制模式、URL 地址可点击、快捷键","支持 生成转发当前内容的链接","支持 折叠后显示数组的长度 或 对象包含的属性个数","支持 对数组只解析第一项 —— SMode","支持 显示输入框光标位置。方便在输入的json格式有问题时，根据 chrome 的提示位置信息定位错误位置","兼容 最后一项后面多出一个逗号: ,"],"obj":{"num":-24,"null":null,"boolean":true},"objList":[{},{"key":"value"}]}',
                jsonResultTemp:[],
                jsonResult: '',
                tab: '    ',
                keyEnd: '"</span>: ',
                arraySampling: false,// 遇到数组，只解析第一个元素
                defaultFold: 997,
                shareLink: ''
            },
            mounted: function () {
                if (localStorage.json_arraySampling !== undefined) {
                    this.arraySampling = localStorage.json_arraySampling === 'true'
                }
                this.SModeStatusChange()
                if (localStorage.json_defaultFold) {
                    this.defaultFold = localStorage.json_defaultFold
                }
                if (localStorage.json_jsonSrc) {
                    this.jsonSrc = localStorage.json_jsonSrc
                }
                let shareId = this.getQueryParamAndClearAll('shareId')
                if (shareId) {
                    this.jsonSrc = '{"提示":"shareId: ' + shareId + ' 对应的 JSON 加载中..."}'
                    this.jsonSrcChange()
                    this.loadJsonSrcByShareId(shareId)
                } else {
                    this.jsonSrcChange()
                }
                if (localStorage.alipayRedBaoNeedShow != '0') {
                    $('#alipay-red-bao-button').show()
                    if (new Date().setHours(0,0,0,0) < localStorage.alipayRedBaoViewTime
                        && localStorage.alipayRedBaoViewTime < new Date().setHours(23,59,59,0)) {
                        $('#alipay-red-bao-button').removeClass('red-point-button')
                    } else {
                        $('#alipay-red-bao-button').addClass('red-point-button')
                    }
                }
            },
            methods: {
                viewAlipayRedBao: function() {
                    localStorage.alipayRedBaoViewTime = new Date().getTime()
                    $('#alipay-red-bao-button').removeClass('red-point-button')
                },
                isArray: function (obj) {
                    return  obj && typeof obj === 'object' && typeof obj.length === 'number' && !(obj.propertyIsEnumerable('length'))
                },
                jsonLinkWarpper: function (str) {
                    return str.replace(this.reLink, '<a class="json_link" target="_blank" href="$1">$1</a>'); 
                },
                genKey: function (key, depth) {
                    this.jsonResultTemp.push("<br><span class='json_key'>")
                    this.jsonResultTemp.push(this.tab.repeat(depth + 1))
                    this.jsonResultTemp.push("\"")
                    this.jsonResultTemp.push($('<div/>').text(key).html())
                    this.jsonResultTemp.push(this.keyEnd)
                },
                genValue: function (obj, depth) {
                    if (!this.jsonResultTemp[this.jsonResultTemp.length - 1].endsWith(this.keyEnd)) { // 冒号后面不换行
                        this.jsonResultTemp.push('<br>')
                        this.jsonResultTemp.push(this.tab.repeat(depth))
                    }
                    var type = obj === null ? 'null' : typeof obj
                    this.jsonResultTemp.push('<span class="json_')
                    this.jsonResultTemp.push(type)
                    this.jsonResultTemp.push('">')
                    if (type === 'string') {
                        this.jsonResultTemp.push('"')
                        this.jsonResultTemp.push(this.jsonLinkWarpper($('<div/>').text(obj === null ? 'null' : obj).html()))
                        this.jsonResultTemp.push('"')
                    } else {
                        this.jsonResultTemp.push(obj === null ? 'null' : obj)
                    }
                    this.jsonResultTemp.push('</span>,')
                },
                genStart: function (start, depth, itemCount) {
                    if (this.jsonResultTemp.length > 0 
                        && !this.jsonResultTemp[this.jsonResultTemp.length - 1].endsWith(this.keyEnd)) { // 冒号后面不换行
                        this.jsonResultTemp.push('<br>')
                        this.jsonResultTemp.push(this.tab.repeat(depth))
                    }
                    this.jsonResultTemp.push(start)
                    if (depth > this.defaultFold || itemCount === 0) {
                        this.jsonResultTemp.push('<i class="uk-icon-angle-right" onClick="unFold(this)">' 
                            + '<span class="fold_icon">...' + itemCount + '</span>'
                            + '</i>'
                            + '<span class="foldContent" style="display:none">')
                    } else {
                        this.jsonResultTemp.push('<i class="uk-icon-angle-down" onClick="fold(this)">' 
                            + '<span class="fold_icon" style="display:none;">...' + itemCount + '</span>'
                            + '</i>'
                            + '<span class="foldContent">')
                    }
                },
                genEnd: function (end, depth) {
                    this.deletLastComma()
                    this.jsonResultTemp.push('<br>')
                    this.jsonResultTemp.push(this.tab.repeat(depth))
    
                    this.jsonResultTemp.push('</span>') // <span class="foldContent">
                    this.jsonResultTemp.push(end)
                    this.jsonResultTemp.push(',')
                },
                deletLastComma: function () {
                    var old = this.jsonResultTemp.pop()
                    var index = old.lastIndexOf(',')
                    var index1 = old.lastIndexOf('{')
                    var index2 = old.lastIndexOf('[')
                    if (index > index1 && index > index2) {
                        this.jsonResultTemp.push(old.substring(0, index))
                        this.jsonResultTemp.push(old.substring(index + 1))
                        return true
                    }
                    this.jsonResultTemp.push(old)
                    return false
                },
                genResult: function (obj, depth) {
                    if (this.isArray(obj)) {
                        this.genStart('[', depth, obj.length)
                        for(var i = 0; i < (this.arraySampling ? Math.min(obj.length, 1) : obj.length); i++) {
                            this.genResult(obj[i], depth + 1)
                        }
                        this.genEnd(']', depth)
                        return
                    }
                    if ((typeof obj) === 'object' && obj !== null) {
                        this.genStart('{', depth, Object.keys(obj).length)
                        for (key in obj) {
                            this.genKey(key, depth)
                            this.genResult(obj[key], depth + 1)
                        }
                        this.genEnd('}', depth)
                        return
                    }
                    this.genValue(obj, depth)
                },
                jsonSrcChange: function () {
                    if (this.jsonSrc === '') {
                        return
                    }
                    try {
                        var obj = JSON.parse(
                            this.jsonSrc
                            .replace(this.reLastComma, " $1")
                        )
                        this.jsonResultTemp = []
                        this.genResult(obj, 0)
                        this.deletLastComma()
                        this.jsonResult = this.jsonResultTemp.join("")
                        if (this.jsonSrc.length < (1024 * 128) 
                            && !this.jsonSrc.startsWith('{"提示":"shareId: ')) {
                            localStorage.json_jsonSrc = this.jsonSrc
                        }
                    } catch (e) {
                        this.jsonResult = e.message
                        var position = parseInt(e.message.substring(e.message.lastIndexOf(' ')))
                        if (position) {
                            // $('#json_src').focus()
                        }
                    }
                },
                SModeStatusChange: function () {
                    localStorage.json_arraySampling = this.arraySampling
                    if (this.arraySampling) {
                        $('#array-sampling-on').show()
                        $('#array-sampling-label').addClass('uk-button-success')
                        $('#array-sampling-off').hide()
                    } else {
                        $('#array-sampling-on').hide()
                        $('#array-sampling-label').removeClass('uk-button-success')
                        $('#array-sampling-off').show()
                    }
                },
                unFoldAll: function (level) {
                    localStorage.json_defaultFold = level - 1
                    this.defaultFold = level - 1
                    if (vm_header_extend_item_1) {
                        vm_header_extend_item_1.level = level
                    }
                    this.traverseChildren(
                        document.getElementById("json_result"),
                        function(element, depth) {
                            if(element.tagName === 'I'){
                                if(depth > level){
                                    fold(element)
                                } else {
                                    unFold(element)
                                }
                            }
                        },
                        0
                    )
                },
                traverseChildren: function (element, func, depth) {
                    for(var i = 0; i < element.childNodes.length; i++){
                        this.traverseChildren(element.childNodes[i], func, depth + 1)
                    }
                    func(element, depth)
                },
                genShareLink: function() {
                    $('#genShareLinkSpinner').show()
                    WithFParams.postForm('/unclassified/jsonShare/create',
                        {
                            "jsonSrc": this.jsonSrc
                        },
                        function (result) {
                            if (result.success) {
                                vm.shareLink = "https://feling.net/json/?shareId=" + result.data
                                if (!localStorage.json_notFirstTimeGenShareLink) {
                                    localStorage.json_notFirstTimeGenShareLink = true
                                }
                            } else {
                                UIkit.modal.alert("生成分享链接失败")
                            }
                        }
                    )
                    .always(function () {
                        $('#genShareLinkSpinner').hide()
                    })
                },
                share: function() {
                    if (localStorage.json_notFirstTimeGenShareLink) {
                        this.genShareLink()
                    } else {
                        UIkit.modal.confirm('此功能需要上传当前输入框的内容, 是否继续?', function () {
                            vm.genShareLink()
                        })
                    }
                },
                getQueryParamAndClearAll: function(key) {
                    var reg = new RegExp("(^|&)" + key + "=([^&]*)(&|$)");
                    var r = window.top.location.search.substr(1).match(reg);
                    // window.top.history.replaceState(null, null, "/json/")
                    if (r != null) {
                        return decodeURIComponent(r[2])
                    }
                    return null;
                },
                loadJsonSrcByShareId: function(shareId) {
                    WithFParams.postForm('/unclassified/jsonShare/get',
                        {
                            "shareId": shareId
                        },
                        function(result) {
                            if (result.success) {
                                vm.jsonSrc = result.data.jsonSrc
                            } else {
                                vm.jsonSrc = '{"提示":"shareId: ' + shareId + ' 对应的 json 加载失败"}'
                            }
                        }
                    ).always(function () {
                        vm.jsonSrcChange()
                    })
                }
            }
        })
    </script>
    
    <script src="//cdn.apihub.net/js/clipboard.min.js"></script>
    <script>
        new ClipboardJS('#copy-compression-jsonSrc', {
            text: function(trigger) {
                return JSON.stringify(JSON.parse(vm.jsonSrc.replace(vm.reLastComma, "$1")))
            }
        }).on('success', function(e) {
            $('#copy-success').show()
            setTimeout(function () {$('#copy-success').hide()} ,900)
        })
        new ClipboardJS('.copy-button').on('success', function(e) {
            $('#copy-success').show()
            setTimeout(function () {$('#copy-success').hide()} ,900)
            e.clearSelection()
            showIcon()
        })
        new ClipboardJS('#copy-share-link', {
            text: function(trigger) {
                return vm.shareLink
            }
        }).on('success', function(e) {
            vm.shareLink = ''
            $('#copy-success').show()
            setTimeout(function () {$('#copy-success').hide()} ,900)
        })
    </script>
    
    <script>
        hotkeys('ctrl+1,ctrl+2,ctrl+3,ctrl+4,ctrl+5,ctrl+0,ctrl+6', function(event,handler) {
            switch(handler.key){
                case "ctrl+1": $('#button-unFoldAll-1').click();break;
                case "ctrl+2": $('#button-unFoldAll-2').click();break;
                case "ctrl+3": $('#button-unFoldAll-3').click();break;
                case "ctrl+4": $('#button-unFoldAll-4').click();break;
                case "ctrl+5": $('#button-unFoldAll-5').click();break;
                case "ctrl+0": $('#button-unFoldAll-n').click();break;
                case "ctrl+6": $('#button-unFoldAll-n').click();break;
            }
        })
        hotkeys('ctrl+m', function(event,handler) {
            $('#array_sampling').click()
        })
    </script>
    
    <li d="header-extend-item-0" class="header-extend-item uk-parent uk-visible-large" data-uk-dropdown="{delay:1500}">
        <a class="uk-navbar-content">快捷键表 <i class="uk-icon-caret-down"></i></a>
        <div class="uk-dropdown uk-dropdown-navbar" style="width:480px;">
            <table class="uk-table">
                <tbody>
                    <tr>
                        <td class="uk-text-left uk-text-bold">ctrl+b 或 ⌘+b</td><td class="uk-text-left">打开/关闭 左侧菜单栏</td>
                    </tr>
                    <tr>
                        <td class="uk-text-left uk-text-bold">ctrl+m</td><td class="uk-text-left">打开/关闭 SMode (对于数组, 只解析它的第一项)</td>
                    </tr>
                    <tr>
                        <td class="uk-text-left uk-text-bold">ctrl+0 或 ctrl+6</td><td class="uk-text-left">完全展开</td>
                    </tr>
                    <tr>
                        <td class="uk-text-left uk-text-bold">ctrl+1, ..., ctrl+5</td><td class="uk-text-left">展开至 1~5 级</td>
                    </tr>
                </tbody>
            </table>
        </div>
    </li>
    <li id="header-extend-item-1" class="header-extend-item uk-navbar-content uk-hidden-small">
        <button id="button-unFoldAll-1" class="uk-button" v-bind:class="{'uk-button-success': level == 1}" onclick="vm.unFoldAll(1)">1级</button>
        <button id="button-unFoldAll-2" class="uk-button" v-bind:class="{'uk-button-success': level == 2}" onclick="vm.unFoldAll(2)">2</button>
        <button id="button-unFoldAll-3" class="uk-button" v-bind:class="{'uk-button-success': level == 3}" onclick="vm.unFoldAll(3)">3</button>
        <button id="button-unFoldAll-4" class="uk-button" v-bind:class="{'uk-button-success': level == 4}" onclick="vm.unFoldAll(4)">4</button>
        <button id="button-unFoldAll-5" class="uk-button" v-bind:class="{'uk-button-success': level == 5}" onclick="vm.unFoldAll(5)">5</button>
        <button id="button-unFoldAll-n" class="uk-button" v-bind:class="{'uk-button-success': level == 998}" onclick="vm.unFoldAll(998)">n级</button>
    </li>
    <script>
        vm_header_extend_item_1 = new Vue({
            el: "#header-extend-item-1",
            data: {
                level: parseInt(vm.defaultFold) + 1
            }
        })
    </script>
    <li id="header-extend-item-2" class="header-extend-item uk-navbar-content">
        <label class="uk-label uk-visible-large uk-button" id="array-sampling-label" for="array_sampling" 
            data-uk-tooltip title="对于数组，只显示它的第一项">SMode: 
            <span id="array-sampling-on" style="display:none;">已开启</span>
            <span id="array-sampling-off" style="display:none;">已关闭</span>
        </label>
        <script>
            if (localStorage.json_arraySampling == 'true') {
                $('#array-sampling-on').show()
                $('#array-sampling-label').addClass('uk-button-success')
                $('#array-sampling-off').hide()
            } else {
                $('#array-sampling-on').hide()
                $('#array-sampling-label').removeClass('uk-button-success')
                $('#array-sampling-off').show()
            }
        </script>
    </li>
    <li id="header-extend-item-4" class="header-extend-item" style="float:right">
        <div id="copy-success" class="uk-alert uk-alert-success" 
            style="display:none;margin-bottom:0px;">
            copied
        </div>
    </li>
    <script>
    $('.header-extend-item').appendTo('#header-extend')
    </script>
     <footer>
         {% include footer.html %}
     </footer>
     {% include baidu_tongji.html %}
 </body>
 
 </html>